/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2021-09-17
 * Version     : v0.1
 * Description : 
 *******************************************************************/
 
/*----------------------------Head file----------------------------*/
#include "ls_ble_type.h"
#include "ls_ble_file.h"
#include "ls_ble_file_api.h"
#include "ls_ble_file_protocol.h"
#include "ls_ble_sdk_config.h"
#include "user_config.h"


#if (LS_BLE_FILE_SVC_ENABLE)

/*----------------------------macro file---------------------------*/
#define FILE_PROTO_LOG_EN		1

#if FILE_PROTO_LOG_EN
#include "ls_ble_log.h"
#define TAG                             "file_pro"
#define FILE_PROTO_LOG(level, ...)	    LS_BLE_LOG_PRINT(level, TAG, __VA_ARGS__)
#else
#define FILE_PROTO_LOG(...)
#endif

/*----------------------------type define--------------------------*/
typedef struct {
	uint8_t frame_seq;
	uint8_t frame_sum;
	uint16_t rest_len;
	uint16_t payload_idx;
}txInfoTace_t;

#pragma pack(1)

typedef struct {
	uint8_t head;
	uint8_t pro_ver;
	uint16_t crc;
	uint8_t cmd;
	uint16_t payload_len;
	uint8_t payload[FILE_FIRST_FRAME_DATA_MAX_SIZE];
}first_frame_t;

typedef struct {
	uint8_t frame_seq;
	uint8_t payload[FILE_REST_FRAME_DATA_MAX_SIZE];
}rest_frame_t;

typedef struct {
	uint8_t head;
	uint8_t pro_ver;
	uint16_t crc;
	uint8_t cmd;
	uint16_t payload_len;
	uint8_t payload[FILE_TX_PKT_PAYLOAD_MAX_SIZE];
}txPkt_t;

typedef struct {
	uint8_t head;
	uint8_t pro_ver;
	uint16_t crc;
	uint8_t cmd;
	uint16_t payload_len;
	uint8_t payload[FILE_FIRST_FRAME_DATA_MAX_SIZE];
}rxPkt_t;

#pragma pack()

/*----------------------------var define---------------------------*/
static txInfoTace_t txInfoTrace;
static txPkt_t txPkt;

static void file_evt_cb(file_evt_t *p_evt);
static file_profile_cb_t file_cb = {
    .evt_handler = file_evt_cb,
};

/*-------------------------func declaration------------------------*/

/*-----------------------------------------------------------------*/

static uint16_t checksum(const uint8_t* pData, uint8_t len)
{
	uint16_t chksum = 0;
	for(uint16_t i=0;i<len;i++) {
		chksum += pData[i];
	}
	return chksum;
}


static bool file_first_frame_upload(txPkt_t* txPkt)
{
    uint16_t tx_len = 0;
    uint8_t tx_buf[20];
	memset(tx_buf, 0, sizeof(tx_buf));
	
	tx_len = txPkt->payload_len + FILE_PACKET_HEAD_SIZE;
    if(tx_len > 20)
        return false;
	
	memcpy(tx_buf, (uint8_t*)txPkt, tx_len);
	if(LS_BLE_SUCCESS == file_notify_data(tx_buf, tx_len)) {
        LS_BLE_LOG_RAW_INFO("CMD tx Data:");
        for(int i=0;i<tx_len;i++) {
            LS_BLE_LOG_RAW_INFO("%x, ", tx_buf[i]);
        }
        LS_BLE_LOG_RAW_INFO("\n");
        return true;
	}

	return false;
}


bool file_upload_msg(uint8_t cmd, uint8_t *payload, uint16_t payload_len)
{
    if(payload_len > FILE_TX_PKT_PAYLOAD_MAX_SIZE)
		return false;

	memset(&txPkt, 0, sizeof(txPkt));
	memset(&txInfoTrace, 0, sizeof(txInfoTrace));
    
    txPkt.head = FILE_PRO_HEAD_B1;
	txPkt.pro_ver = FILE_PRO_VER_B2;
	txPkt.cmd = cmd;
	txPkt.payload_len = payload_len;	
	memcpy(txPkt.payload, payload, payload_len);
	txPkt.crc = checksum(&txPkt.cmd, txPkt.payload_len + 3);
	
	txInfoTrace.payload_idx = 0;
	txInfoTrace.rest_len = txPkt.payload_len;
	file_first_frame_upload(&txPkt);

	return true;
}


static void file_evt_cb(file_evt_t *p_evt)
{
    ls_ble_file_cb_evt_param_t evt_param;
    evt_param.len = 0;

    switch(p_evt->evt_type)
    {
        case FILE_EVT_NOTIFICATION_ENABLED: {
            evt_param.evt = LS_BLE_FILE_CB_EVT_NTF_ENABLE;
            ls_ble_file_callback(&evt_param);
        } break;
        
        case FILE_EVT_NOTIFICATION_DISABLED: {
            evt_param.evt = LS_BLE_FILE_CB_EVT_NTF_DISABLE;
            ls_ble_file_callback(&evt_param);
        } break;

        /*case FILE_EVT_NOTIFICATION_COMPLETE: {
            evt_param.evt = LS_BLE_FILE_CB_EVT_NTF_COMPLETE;
            ls_ble_file_callback(&evt_param);
        } break;*/

        case FILE_EVT_RECEIVE_CMD: {
            if(p_evt->length > sizeof(rxPkt_t) || p_evt->length <= 0)
                return;
    
            rxPkt_t* rx = (rxPkt_t*)p_evt->p_data;
            
            if(FILE_PRO_HEAD_B1 != rx->head || FILE_PRO_VER_B2 != rx->pro_ver) {
                FILE_PROTO_LOG(LOG_LVL_ERROR, "Err file pro id: %x, %x.\n", rx->head, rx->pro_ver);
                return;
            }

            if(rx->crc != checksum(&rx->cmd, rx->payload_len + 3)) {
                FILE_PROTO_LOG(LOG_LVL_ERROR, "Err file chksum: %x, %x.\n", rx->crc, checksum(&rx->cmd, rx->payload_len + 3));
                return;
            }
            evt_param.evt = LS_BLE_FILE_CB_EVT_RX_CMD_PAYLOAD;
            evt_param.cmd = rx->cmd;
            evt_param.p_data = rx->payload;
            evt_param.len = rx->payload_len;
            ls_ble_file_callback(&evt_param);
        } break;


        case FILE_EVT_RECEIVE_FILE_DATA: {
            evt_param.evt = LS_BLE_FILE_CB_EVT_RX_FILE_DATA;
            evt_param.p_data = p_evt->p_data;
            evt_param.len = p_evt->length;
            ls_ble_file_callback(&evt_param);
        } break;
        
        default:
            break;
    }
}


void file_protocol_init(void)
{
    file_service_init(&file_cb);
}


#endif      //#if (LS_BLE_FILE_SVC_ENABLE)
